﻿#region 程序集引用
using System;
using System.Security.Cryptography;
using System.IO;
using System.Text;
#endregion

#region 版权注释
/*===========================================================================
// Copyright (C) 2017 Zhang.cn，并保留所有 
// 作者：吴岸标 QQ:405403610
// 创建日期：2017-09-03
// 功能描述： 程序安全相关的操作方法 如加密方法等
===========================================================================*/
#endregion

namespace Zhang
{
    namespace Utils
    {
        /// <summary>
        /// 程序安全相关的操作方法 如加密方法等
        /// </summary>
        public static class Security
        {
            public static string EnAes(string plainText)
            {
                byte[] key = new byte[32] { 22, 22, 22, 22, 33, 33, 33, 33, 44, 44, 44, 44, 55, 55, 55, 55, 66, 97, 45, 81, 85, 192, 67, 58, 185, 198, 33, 72, 153, 52, 76, 29 };
                byte[] iv = new byte[16] { 55, 52, 33, 44, 66, 66, 185, 47, 90, 109, 74, 58, 185, 168, 33, 65 };
                return Convert.ToBase64String(enAes(plainText, key, iv));
            }

            public static string DeAes(string cipherText)
            {
                byte[] key = new byte[32] { 22, 22, 22, 22, 33, 33, 33, 33, 44, 44, 44, 44, 55, 55, 55, 55, 66, 97, 45, 81, 85, 192, 67, 58, 185, 198, 33, 72, 153, 52, 76, 29 };
                byte[] iv = new byte[16] { 55, 52, 33, 44, 66, 66, 185, 47, 90, 109, 74, 58, 185, 168, 33, 65 };
                return deAes(Convert.FromBase64String(cipherText), key, iv);
            }

            public static string DeAes(string ecryptData, string key, string iv) {
                byte[] keys = Convert.FromBase64String(key);
                byte[] ivs = Convert.FromBase64String(iv);
                return deAes(Convert.FromBase64String(ecryptData), keys, ivs);
            }

            /// <summary>
            ///  AES-128-CBC，数据采用PKCS#7
            /// </summary>
            /// <param name="decryptString"></param>
            /// <param name="decryptKey"></param>
            /// <param name="iv"></param>
            /// <returns></returns>
            public static string DeAesPKC7(string decryptString, string decryptKey,string iv)
            {
                try
                {
                    byte[] rgbKey = Convert.FromBase64String(decryptKey);
                    byte[] rgbIV = Convert.FromBase64String(iv);
                    byte[] inputByteArray = Convert.FromBase64String(decryptString);
                    var aes = new AesCryptoServiceProvider();
                    aes.Mode = CipherMode.CBC;
                    aes.Padding = PaddingMode.PKCS7;
                    MemoryStream mStream = new MemoryStream();
                    CryptoStream cStream = new CryptoStream(mStream, aes.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
                    cStream.Write(inputByteArray, 0, inputByteArray.Length);
                    cStream.FlushFinalBlock();
                    return Encoding.UTF8.GetString(mStream.ToArray());
                }
                catch
                {
                    return decryptString;
                }
            }
            private static byte[] enAes(string plainText, byte[] key, byte[] iv)
            {
                if (plainText == null || plainText.Length <= 0)
                    throw new ArgumentNullException("plainText");
                if (key == null || key.Length <= 0)
                    throw new ArgumentNullException("key");
                if (iv == null || iv.Length <= 0)
                    throw new ArgumentNullException("iv");
                MemoryStream msEncrypt = null;
                CryptoStream csEncrypt = null;
                StreamWriter swEncrypt = null;
                Aes aesAlg = null;
                try
                {
                    aesAlg = Aes.Create();
                    aesAlg.Key = key;
                    aesAlg.IV = iv;
                    ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
                    msEncrypt = new MemoryStream();
                    csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
                    swEncrypt = new StreamWriter(csEncrypt);
                    swEncrypt.Write(plainText);
                }
                finally
                {
                    if (swEncrypt != null)
                        swEncrypt.Close();
                    if (csEncrypt != null)
                        csEncrypt.Close();
                    if (msEncrypt != null)
                        msEncrypt.Close();
                    if (aesAlg != null)
                        aesAlg.Clear();
                }
                return msEncrypt.ToArray();
            }

            private static string deAes(byte[] cipherText, byte[] key, byte[] iv)
            {
                if (cipherText == null || cipherText.Length <= 0)
                    throw new ArgumentNullException("cipherText");
                if (key == null || key.Length <= 0)
                    throw new ArgumentNullException("key");
                if (iv == null || iv.Length <= 0)
                    throw new ArgumentNullException("iv");
                MemoryStream msDecrypt = null;
                CryptoStream csDecrypt = null;
                StreamReader srDecrypt = null;
                Aes aesAlg = null;
                string plaintext = null;
                try
                {
                    aesAlg = Aes.Create();
                    aesAlg.Key = key;
                    aesAlg.IV = iv;
                    ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
                    msDecrypt = new MemoryStream(cipherText);
                    csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
                    srDecrypt = new StreamReader(csDecrypt);
                    plaintext = srDecrypt.ReadToEnd();
                }
                finally
                {
                    if (srDecrypt != null)
                        srDecrypt.Close();
                    if (csDecrypt != null)
                        csDecrypt.Close();
                    if (msDecrypt != null)
                        msDecrypt.Close();
                    if (aesAlg != null)
                        aesAlg.Clear();
                }
                return plaintext;
            }

            #region md5加密
            /// <summary>
            /// md5加密
            /// </summary>
            /// <param name="md5Content">要加密的字符串</param>
            /// <param name="code">加密方式16位或32位</param>
            /// <returns>加密后的字符串</returns>
            public static string MD5(string md5Content, int code)
            {
                byte[] arrByte;
                byte[] arrResult;
                string result;
                MD5CryptoServiceProvider md5;

                md5 = new MD5CryptoServiceProvider();
                arrByte = System.Text.Encoding.UTF8.GetBytes(md5Content);
                arrResult = md5.ComputeHash(arrByte);
                result = "";

                //字节类型的数组转换为字符串 
                for (int i = 0; i < arrResult.Length; i++)
                {
                    //16进制转换 
                    result = result + arrResult[i].ToString("X").PadLeft(2, '0');
                }

                if (code == 16) //16位MD5加密（取32位加密的9~25字符） 
                {
                    result = result.Substring(8, 16);
                }

                result = result.ToUpper();
                return result;
            }
            #endregion

            #region  字符串对称加密
            /// <summary>
            /// 字符串加密
            /// 密钥为空时返回:密钥不能为空
            /// 密钥长度大于明文长度时返回:密钥太长
            /// 密钥为不识别字符时返回:请换密钥
            /// </summary>
            /// <param name="plainText">要加密的字符串</param>
            /// <param name="key">密钥不可以为空且只能是字母或数字</param>
            /// <returns>返回加密后的密文及提示信息</returns>
            public static string Encrypt(string plainText, string key)
            {
                Random rnd = new Random();
                char[] chr = plainText.ToCharArray();
                char[] temparr = new char[plainText.Length];
                char[] result = new char[chr.Length + key.Length];

                if (key.Length == 0)
                    return "密钥不能为空";
                if (key.Length > plainText.Length)
                    return "密钥太长";
                //给密钥加密
                for (int i = 0; i < key.Length; i++)
                {
                    int temp = (int)(key[i]);
                    if (temp < 21 || temp > 122)
                        return "请换密钥";
                    int index = i + i * (plainText.Length / key.Length);
                    result[index] = (char)(temp + i % 5);
                }
                if (plainText.Length % 2 == 0) //偶数个字符时
                {
                    int i, j;
                    for (i = 0, j = 0; i < plainText.Length / 2; i++, j++)
                    {
                        temparr[j] = chr[i];
                        j = j + 1;
                        temparr[j] = chr[plainText.Length - i - 1];
                    }
                }
                else //奇数个字符
                {
                    int i, j;

                    for (i = 0, j = 0; i < (plainText.Length - 1) / 2; i++, j++)
                    {
                        temparr[j] = chr[i];
                        char str = temparr[j];
                        j = j + 1;
                        temparr[j] = chr[plainText.Length - i - 1];
                        str = temparr[j];
                    }
                    temparr[j] = chr[plainText.Length / 2];
                }
                //将密钥插入密文中
                for (int i = 0, j = 0; i < result.Length; i++)
                {
                    if (result[i] != '\0')
                        continue;
                    else
                    {
                        result[i] = temparr[j];
                        j++;
                    }
                }

                return OpString.GetString(result);
            }
            #endregion

            #region 对称加密密文解密
            /// <summary>
            /// 密文解密,若密钥不对则返回“密码错误”提示
            /// </summary>
            /// <param name="cipherText">密文内容</param>
            /// <param name="key">密钥</param>
            /// <returns>返回明文或错误信息;若密钥不对则返回“密码错误”提示</returns>
            public static string DelCrypt(string cipherText, string key)
            {
                if (key.Length == 0)
                    return "密钥错误";
                if (key.Length > cipherText.Length)
                    return "密钥错误";

                int txtlength = cipherText.Length - key.Length;
                char[] temp = new char[txtlength];
                char[] result = new char[txtlength];
                char[] chr = cipherText.ToCharArray();

                //解密密钥
                for (int i = 0, j = 0, k = 0; i < chr.Length; i++)
                {
                    if ((i == j + j * (txtlength / key.Length)) && (j < key.Length))
                    {
                        int tempintdata = (int)(chr[i]) - j % 5 - (int)(key[j]);
                        if (tempintdata != 0)
                            return "密钥错误";
                        else
                            j++;
                    }
                    else
                    {
                        temp[k] = chr[i];
                        k++;
                    }
                }
                if (txtlength % 2 == 0)
                {
                    for (int i = 0, j = 0; i < temp.Length / 2; i++, j++)
                    {
                        result[i] = temp[j];
                        result[temp.Length - i - 1] = temp[++j];
                    }
                }
                else
                {
                    int i, j;
                    for (i = 0, j = 0; i < (temp.Length - 1) / 2; i++, j++)
                    {
                        result[i] = temp[j];
                        result[temp.Length - i - 1] = temp[++j];
                    }
                    result[i] = temp[j];
                }
                return OpString.GetString(result);
            }
            #endregion


            #region RSA

            /// <summary>
            ///  生成密钥对。
            /// </summary>
            /// <param name="xmlKeys">返回的私钥</param>
            /// <param name="xmlPublicKey">返回的公钥</param>

            public static void RsaKey(out string xmlKeys, out string xmlPublicKey)
            {
                try
                {
                    System.Security.Cryptography.RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
                    xmlKeys = rsa.ToXmlString(true);
                    xmlPublicKey = rsa.ToXmlString(false);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }


            /// <summary>
            /// RSA加密
            /// </summary>
            /// <param name="rawInput"></param>
            /// <param name="publicKey"></param>
            /// <returns></returns>
            public static string RsaEncrypt(string rawInput, string publicKey)
            {
                if (string.IsNullOrEmpty(rawInput))
                {
                    return string.Empty;
                }

                if (string.IsNullOrWhiteSpace(publicKey))
                {
                    throw new ArgumentException("Invalid Public Key");
                }

                using (var rsaProvider = new RSACryptoServiceProvider())
                {
                    var inputBytes = Encoding.UTF8.GetBytes(rawInput);//有含义的字符串转化为字节流
                    rsaProvider.FromXmlString(publicKey);//载入公钥
                    int bufferSize = (rsaProvider.KeySize / 8) - 11;//单块最大长度
                    var buffer = new byte[bufferSize];
                    using (MemoryStream inputStream = new MemoryStream(inputBytes),
                         outputStream = new MemoryStream())
                    {
                        while (true)
                        { //分段加密
                            int readSize = inputStream.Read(buffer, 0, bufferSize);
                            if (readSize <= 0)
                            {
                                break;
                            }

                            var temp = new byte[readSize];
                            Array.Copy(buffer, 0, temp, 0, readSize);
                            var encryptedBytes = rsaProvider.Encrypt(temp, false);
                            outputStream.Write(encryptedBytes, 0, encryptedBytes.Length);
                        }
                        return Convert.ToBase64String(outputStream.ToArray());//转化为字节流方便传输
                    }
                }
            }

            /// <summary>
            /// RSA解密
            /// </summary>
            /// <param name="encryptedInput"></param>
            /// <param name="privateKey"></param>
            /// <returns></returns>
            public static string RsaDecrypt(string encryptedInput, string privateKey)
            {
                if (string.IsNullOrEmpty(encryptedInput))
                {
                    return string.Empty;
                }

                if (string.IsNullOrWhiteSpace(privateKey))
                {
                    throw new ArgumentException("Invalid Private Key");
                }

                using (var rsaProvider = new RSACryptoServiceProvider())
                {
                    var inputBytes = Convert.FromBase64String(encryptedInput);
                    rsaProvider.FromXmlString(privateKey);
                    int bufferSize = rsaProvider.KeySize / 8;
                    var buffer = new byte[bufferSize];
                    using (MemoryStream inputStream = new MemoryStream(inputBytes),
                         outputStream = new MemoryStream())
                    {
                        while (true)
                        {
                            int readSize = inputStream.Read(buffer, 0, bufferSize);
                            if (readSize <= 0)
                            {
                                break;
                            }

                            var temp = new byte[readSize];
                            Array.Copy(buffer, 0, temp, 0, readSize);
                            var rawBytes = rsaProvider.Decrypt(temp, false);
                            outputStream.Write(rawBytes, 0, rawBytes.Length);
                        }
                        return Encoding.UTF8.GetString(outputStream.ToArray());
                    }
                }
            }
            #endregion
        }
    }
}
